package expression

import (
	"log"
	"mini-sql/config"
	"mini-sql/model"
)

type CompareFunction func(*model.Expr, *model.Expr) bool

func GetCompareFunction(exprType model.ExprType) CompareFunction {
	switch exprType {
	case model.ExprTypeCmpEq:
		return BoolOpEQ
	case model.ExprTypeCmpNotEq:
		return BoolOpNotEQ
	case model.ExprTypeCmpGt:
		return BoolOpGT
	case model.ExprTypeCmpGtEq:
		return BoolOpGTEQ
	case model.ExprTypeCmpLt:
		return BoolOpLT
	case model.ExprTypeCmpLtEq:
		return BoolOpLTEQ
	case model.ExprTypeAnd:
		return BoolOpAnd
	case model.ExprTypeOr:
		return BoolOpOr
	}
	return nil
}

func EvalExpr(expr *model.Expr, tuple *model.TableTuple) *model.Expr {
	if expr.ExprType == model.ExprTypeAnd {
		// AND表达式可以提前中断
		a := EvalExpr(expr.GetChild(0), tuple)
		if !a.ToBool() {
			return model.NewFalseExpr()
		}
		b := EvalExpr(expr.GetChild(1), tuple)
		return model.NewExprFromBool(BoolOpAnd(a, b))
	}

	// 其他比较操作符
	compareFunction := GetCompareFunction(expr.ExprType)
	if compareFunction != nil {
		a := EvalExpr(expr.GetChild(0), tuple)
		b := EvalExpr(expr.GetChild(1), tuple)
		return model.NewExprFromBool(compareFunction(a, b))
	}

	if expr.ExprType == model.ExprTypeNameId {
		return getTupleValue(tuple, expr.StrValue)
	}

	if expr.IsValue() {
		return expr
	}

	if config.DebugExecutor {
		log.Printf("EvalExpr: unsupported expr: %v", expr)
	}
	return expr
}

func getTupleValue(tuple *model.TableTuple, name string) *model.Expr {
	if name == model.TableRowIdName {
		return &model.Expr{
			ExprType: model.ExprTypeInt64,
			IntValue: tuple.RowID,
		}
	}
	for _, item := range tuple.Fields {
		if item.Name == name {
			return model.NewExprFromValue(item.Value)
		}
	}
	return model.NewNullExpr()
}
